//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using OpenLS.Spreadsheet.Extensibility;

namespace OpenLS.Spreadsheet.Expressions
{
    internal interface  ICellEnumerator
    {
        IRange ToRange();
    }
    internal abstract class BinaryRangeExpression : CellEnumeratorExpression
    {
        private readonly Expression _left;

        private readonly Expression _right;

        protected BinaryRangeExpression(Expression left, Expression right)
        {
            Contract.Requires(left != null);
            Contract.Requires(right != null);
            _left = left;
            _right = right;
        }
        public override Worksheet Worksheet
        {
            get
            {
                if (Left is CellEnumeratorExpression)
                    return ((CellEnumeratorExpression)Left).Worksheet;
                if (Right is CellEnumeratorExpression)
                    return ((CellEnumeratorExpression)Right).Worksheet;
                throw new NotImplementedException();
            }
        }

        public Expression Left
        {
            get { return _left; }
        }

        public Expression Right
        {
            get { return _right; }
        }

        public override sealed IEnumerable<Expression> GetSubExpressions()
        {
            yield return Left;
            yield return Right;
        }

        public override sealed Expression Offset(CellRelativeAddress a)
        {
            return CreateExpression((CellEnumeratorExpression) Left.Offset(a),
                                    (CellEnumeratorExpression) Right.Offset(a));
        }

        protected abstract Expression CreateExpression(CellEnumeratorExpression left, CellEnumeratorExpression right);


        public override IEnumerable<IDependencyNode> GetPrecedents(EvaluationContext context)
        {
            foreach (IDependencyNode c in Left.GetPrecedents(context))
                yield return c;
            foreach (IDependencyNode c in Right.GetPrecedents(context))
                yield return c;
        }

        protected internal override sealed ICellEnumerator GetCellsValue(EvaluationContext context)
        {
            object leftValue = Left.GetObject(context);
            object rightValue = Right.GetObject(context);
            if (leftValue is Error)
                throw new ErrorException((Error)leftValue);
            if (rightValue is Error)
                throw new ErrorException((Error)rightValue);
            if (!(leftValue is ICellEnumerator) || !(rightValue is ICellEnumerator))
            {
                throw new ErrorException(Errors.ValueError);
            }
            return CreateCellsValue(((ICellEnumerator)leftValue), ((ICellEnumerator)rightValue));
        }

        protected abstract ICellEnumerator CreateCellsValue(ICellEnumerator enumerator, ICellEnumerator cellEnumerator);
    }
}